/*
   Manage std::thread Object
*/


/*
    构造std::thread对象
    std::thread可以与任何可调用（callable）类型一同工作
    可以将一个带有函数调用操作符的类的实例传递给std::thread的构造函数来进行代替
*/
#include <thread>

class  background_task
{
public:
    void operator() () const {  // 
        // do_something();
        // do_something_else();
    }
};

background_task f;
std::thread my_thread{f};   // f is copied to the thread

// There will be ambiguity
std::thread my_thread(background_task());  // Incoming equivalent to [](){ do_something(); do_something_else();}
// Actually need to pass in the object
std::thread my_thread((background_task())); // or
std::thread my_thread{background_task()}; // Unified initialization syntax

/*** 
 * {} () Initialization difference
 * https://blog.csdn.net/weixin_42817477/article/details/108981980
 * 总结来说 只要形参中没有任何一个具备std::initializer_list型别，那么小括号和大括号的意义就没有区别
 * 优先使用{}
***/


/*
    启动运行中
*/
#include <iostream>
#include <thread>

void do_something(int val) {
    std::cout << val << std::endl;
}
struct func
{
    int& i; // there is &
    func(int& i_): i{i_} {

    }
    void operator() () {
        for(unsigned j = 0; j < 1000000; ++j) {
            do_something(i);    // 对悬空引用可能的访问 tips1
        }
    }
};

////// std::thread 等待(join)或不等待(detach)的情况     //////
void oops() {
    int some_local_state = 0;
    func my_func(some_local_state);
    std::thread my_thread(my_func);
    my_thread.detach();     // Do not wait for the thread to complete, join() contrary    
}/***   Run here
  *  some_local_state will be released and destroyed
  *  tips1: i is unpredictable
  * 
***/

////// 在异常环境下的等待（均是需要等待线程完成的情况，直接detach的情况可忽略） //////
void f1() {
    int some_local_state = 0;
    func my_func(some_local_state);
    std::thread t(my_func);
    try {
        // do_something_in_current_thread();   functions that trigger exceptions
    } catch(...) {
        t.join();
        throw;
    }
    t.join();
}
// other way 使用RAII(资源获取即初始化)等待线程完成
class thread_guard {
    std::thread& t;
public:
    explicit thread_guard(std::thread& t_): t(t_) {

    }
    ~thread_guard(){
        if(t.joinable()) {
            t.join();
        }
    }
    // 禁止拷贝操作（防止子类的篡改）
    thread_guard(thread_guard const&) = delete;     // 做标记，确保不会被赋值或复制，加delete直接报错（防止子类调用默认构造函数）
    thread_guard& operator = (thread_guard const&) = delete;   // 防止子类调用默认赋值操作符重载
};
void f2() {
    int some_local_state = 0;
    func my_func(some_local_state);
    std::thread t(my_func);
    thread_guard g(t);

    // do_something_in_current_thread();   functions that trigger exceptions
}
/*** 
 * RAII惯用法
 * https://blog.csdn.net/qq135595696/article/details/121411724
 * 总结来说 目的是保证资源的释放顺序与获取顺序严格相反
 *      而这和在栈空间上的局部对象称为自动存储对象的行为，高度耦合
 *      故利用构造函数和析构函数的性质以及它们与异常处理的交互作用的方法
***/

////// 在后台运行的线程(detach之后的情况)    //////
std::thread t{background_task()};
t.detach();     // unix守护进程概念，此线程被成为守护线程
/***
 * 存在意义（因为这样的线程长时间运行的，甚至在程序的整个生命周期）
 * 例如监控文件系统，清除对象缓存中未使用项或是优化数据结构
 * 鉴别线程何时完成的机制，或者线程被用作“即用即忘”任务
 ***/
assert(!t.joinable());      // 不再与实际线程相关联，也不能被加入

// eg：分离线程以处理其他文档
/* 未定义函数均以字面意义作为功能
void edit_document(std::string const& filename) {
    open_document_and_display_gui(filename);
    while(!done_editing()) {
        user_command cmd = get_user_input();
        if(cmd.type == open_new_document) {
            std::string const new_name = get_filename_from_user();
            std::thread t(edit_document, new_name);     // 启用新线程来处理新要打开的文件
            t.detach();
        } else {
            process_user_input(cmd);
        }
    }
}*/
